#include "Universe.h"

Universe::Universe(unsigned int sizeX, unsigned int sizeY)
{
    matrix.resize(sizeX);
    for(int i = 0 ; i < sizeX ; ++i)
        matrix[i].resize(sizeY);
        
    this->sizeX = sizeX;
    this->sizeY = sizeY;
}

Universe::~Universe()
{
    list<Shell *>::iterator iter;
    iter = elements.begin();
    while(iter != elements.end())
    {
        delete (*iter);
        ++iter;
    }
}

bool Universe::moveElementTo(Shell * shell, const Direction & dir)
{    
    Position position = shell->getPosition();

    if(isOutsideUniverse(position, dir))
        return false;
    
    position.X += dir.getDirectionX();
    position.Y += dir.getDirectionY();
    
    return moveElementTo(shell, position);
}

bool Universe::moveElementTo(Shell * shell, const Position & position)
{
    /* ELSE */
    if(ActiveElementExistsAt(position))
        return false;
    
    if(shell->isActive())
        matrix[shell->getPosition().X][shell->getPosition().Y].pop_front();
    
    shell->setActive(true);
        
    matrix[position.X][position.Y].push_front(shell);
    
    shell->setPosition(position);

    return true;
}

bool Universe::registerElement(Shell * shell)
{
    //zou moeten checken al nie reeds erin was   
    elements.push_back(shell);
        
    /* if all is wel aan good */
    return true;
}

//void Universe::deleteElement(Element * newElement);
Shell * Universe::getElementAt(const Position & position)
{
    if(position.X < sizeX && position.Y < sizeY)
        if(matrix[position.X][position.Y].size())
            return matrix[position.X][position.Y].front();
            
    return '\0';
}

// const, for non evil stuff
bool Universe::ActiveElementExistsAt(const Position & position) const
{
    if(position.X < sizeX && position.Y < sizeY)
        if(matrix[position.X][position.Y].size())
            return matrix[position.X][position.Y].front()->isActive();
    
    return false;
}

void Universe::spawnAllElements()
{
    list<Shell *>::iterator iter;
    iter = elements.begin();
    while(iter != elements.end())
    {
        (*iter)->spawn();
        ++iter;
    }
}

unsigned int Universe::getYsize() const
{
    return sizeY;
}
unsigned int Universe::getXsize() const
{
    return sizeX;
}

bool Universe::isOutsideUniverse(const Position & pos) const
{
    Direction dir;
    return isOutsideUniverse(pos, dir);
}

bool Universe::isOutsideUniverse(const Position & pos, const Direction & dir) const
{
    bool outsideFieldLeft  = ((pos.X == 0) && (dir.getDirectionX() == -1 ));
    bool outsideFieldUp    = ((pos.Y == 0) && (dir.getDirectionY() == -1 ));
    
    bool outsideFieldRight = ((pos.X + dir.getDirectionX()) >= sizeX);
    bool outsideFieldDown  = ((pos.Y + dir.getDirectionY()) >= sizeY);
    
    if(outsideFieldLeft || outsideFieldRight || outsideFieldUp || outsideFieldDown)
        return true;
    else
        return false;
}

